<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- saved from url=(0101)http://docs.google.com/a/mckoss.com/View?docID=0AcUE2vPPoFO7ZGc3andnZG5fNWNrOTR4NWdw&revision=_latest -->
<HTML><HEAD><META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<SCRIPT>function b(c){this.t={};this.tick=function(d,e,a){a=a?a:(new Date).getTime();this.t[d]=[a,e]};this.tick("start",null,c)}var f=new b;window.jstiming={Timer:b,load:f};try{window.jstiming.pt=window.gtbExternal&&window.gtbExternal.pageT()||window.external&&window.external.pageT}catch(g){};
</SCRIPT>

<META name="robots" content="noarchive">
<!-- <BASE target="_top"> --><BASE href="." target="_top">
<TITLE>TimeScore - System for Proces...</TITLE>
<STYLE type="text/css">
/* default css */
table {
font-size: 1em;
line-height: inherit;
border-collapse: collapse;
}
tr {
text-align: left;
}
div, address, ol, ul, li, option, select {
margin-top: 0px;
margin-bottom: 0px;
}
p {
margin: 0px;
}
pre {
font-family: Courier New;
white-space: pre-wrap;
margin:0;
}
body {
margin: 6px;
padding: 0px;
font-family: Verdana, sans-serif;
font-size: 10pt;
background-color: #ffffff;
}
img {
-moz-force-broken-image-icon: 1;
}
@media screen {
html.pageview {
background-color: #f3f3f3 !important;
}
body {
min-height: 1100px;
counter-reset: __goog_page__;
}
* html body {
height: 1100px;
}
.pageview body {
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 2px solid #bbb;
border-bottom: 2px solid #bbb;
width: 648px !important;
margin: 15px auto 25px;
padding: 40px 50px;
}
/* IE6 */
* html {
overflow-y: scroll;
}
* html.pageview body {
overflow-x: auto;
}
/* Prevent repaint errors when scrolling in Safari. This "Star-7" css hack
targets Safari 3.1, but not WebKit nightlies and presumably Safari 4.
That's OK because this bug is fixed in WebKit nightlies/Safari 4 :-). */
html*#wys_frame::before {
content: '\A0';
position: fixed;
overflow: hidden;
width: 0;
height: 0;
top: 0;
left: 0;
}
.writely-callout-data {
display: none;
*display: inline-block;
*width: 0;
*height: 0;
*overflow: hidden;
}
.writely-footnote-marker {
background-image: url('images/footnote_doc_icon.gif');
background-color: transparent;
background-repeat: no-repeat;
width: 7px;
overflow: hidden;
height: 16px;
vertical-align: top;
-moz-user-select: none;
}
.editor .writely-footnote-marker {
cursor: move;
}
.writely-footnote-marker-highlight {
background-position: -15px 0;
-moz-user-select: text;
}
.writely-footnote-hide-selection ::-moz-selection, .writely-footnote-hide-selection::-moz-selection {
background: transparent;
}
.writely-footnote-hide-selection ::selection, .writely-footnote-hide-selection::selection {
background: transparent;
}
.writely-footnote-hide-selection {
cursor: move;
}
.editor .writely-comment-yellow {
background-color: #FF9;
background-position: -240px 0;
}
.editor .writely-comment-yellow-hover {
background-color: #FF0;
background-position: -224px 0;
}
.editor .writely-comment-blue {
background-color: #C0D3FF;
background-position: -16px 0;
}
.editor .writely-comment-blue-hover {
background-color: #6292FE;
background-position: 0 0;
}
.editor .writely-comment-orange {
background-color: #FFDEAD;
background-position: -80px 0;
}
.editor .writely-comment-orange-hover {
background-color: #F90;
background-position: -64px 0;
}
.editor .writely-comment-green {
background-color: #99FBB3;
background-position: -48px 0;
}
.editor .writely-comment-green-hover {
background-color: #00F442;
background-position: -32px 0;
}
.editor .writely-comment-cyan {
background-color: #CFF;
background-position: -208px 0;
}
.editor .writely-comment-cyan-hover {
background-color: #0FF;
background-position: -192px 0;
}
.editor .writely-comment-purple {
background-color: #EBCCFF;
background-position: -144px 0;
}
.editor .writely-comment-purple-hover {
background-color: #90F;
background-position: -128px 0;
}
.editor .writely-comment-magenta {
background-color: #FCF;
background-position: -112px 0;
}
.editor .writely-comment-magenta-hover {
background-color: #F0F;
background-position: -96px 0;
}
.editor .writely-comment-red {
background-color: #FFCACA;
background-position: -176px 0;
}
.editor .writely-comment-red-hover {
background-color: #FF7A7A;
background-position: -160px 0;
}
.editor .writely-comment-marker {
background-image: url('images/markericons_horiz.gif');
background-color: transparent;
padding-right: 11px;
background-repeat: no-repeat;
width: 16px;
height: 16px;
-moz-user-select: none;
}
.editor .writely-comment-hidden {
padding: 0;
background: none;
}
.editor .writely-comment-marker-hidden {
background: none;
padding: 0;
width: 0;
}
.editor .writely-comment-none {
opacity: .2;
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
-moz-opacity: .2;
}
.editor .writely-comment-none-hover {
opacity: .2;
filter:progid:DXImageTransform.Microsoft.Alpha(opacity=20);
-moz-opacity: .2;
}
.br_fix span+br:not(:-moz-last-node) {
position:relative;
left: -1ex
}
#cb-p-tgt {
font-size: 8pt;
padding: .4em;
background-color: #ddd;
color: #333;
}
#cb-p-tgt-can {
text-decoration: underline;
color: #36c;
font-weight: bold;
margin-left: 2em;
}
#cb-p-tgt .spin {
width: 16px;
height: 16px;
background: url(//ssl.gstatic.com/docs/clipboard/spin_16o.gif) no-repeat;
}
}
h6 { font-size: 8pt }
h5 { font-size: 8pt }
h4 { font-size: 10pt }
h3 { font-size: 12pt }
h2 { font-size: 14pt }
h1 { font-size: 18pt }
blockquote {padding: 10px; border: 1px #DDD dashed }
.webkit-indent-blockquote { border: none; }
a img {border: 0}
.pb {
border-width: 0;
page-break-after: always;
/* We don't want this to be resizeable, so enforce a width and height
using !important */
height: 1px !important;
width: 100% !important;
}
.editor .pb {
border-top: 1px dashed #C0C0C0;
border-bottom: 1px dashed #C0C0C0;
}
div.google_header, div.google_footer {
position: relative;
margin-top: 1em;
margin-bottom: 1em;
}
/* Table of contents */
.editor div.writely-toc {
background-color: #f3f3f3;
border: 1px solid #ccc;
}
.writely-toc > ol {
padding-left: 3em;
font-weight: bold;
}
ol.writely-toc-subheading {
padding-left: 1em;
font-weight: normal;
}
/* IE6 only */
* html writely-toc ol {
list-style-position: inside;
}
.writely-toc-none {
list-style-type: none;
}
.writely-toc-decimal {
list-style-type: decimal;
}
.writely-toc-upper-alpha {
list-style-type: upper-alpha;
}
.writely-toc-lower-alpha {
list-style-type: lower-alpha;
}
.writely-toc-upper-roman {
list-style-type: upper-roman;
}
.writely-toc-lower-roman {
list-style-type: lower-roman;
}
.writely-toc-disc {
list-style-type: disc;
}
/* Ordered lists converted to numbered lists can preserve ordered types, and
vice versa. This is confusing, so disallow it */
ul[type="i"], ul[type="I"], ul[type="1"], ul[type="a"], ul[type="A"] {
list-style-type: disc;
}
ol[type="disc"], ol[type="circle"], ol[type="square"] {
list-style-type: decimal;
}
/* end default css */
/* custom css */
/* end custom css */
/* ui edited css */
body {
font-family: Verdana;
font-size: 12.0pt;
line-height: normal;
background-color: #ffffff;
}
/* end ui edited css */
/* editor CSS */
.editor a:visited {color: #551A8B}
.editor table.zeroBorder {border: 1px dotted gray}
.editor table.zeroBorder td {border: 1px dotted gray}
.editor table.zeroBorder th {border: 1px dotted gray}
.editor div.google_header, .editor div.google_footer {
border: 2px #DDDDDD dashed;
position: static;
width: 100%;
min-height: 2em;
}
.editor .misspell {background-color: yellow}
.editor .writely-comment {
font-size: 9pt;
line-height: 1.4;
padding: 1px;
border: 1px dashed #C0C0C0
}
/* end editor CSS */
</STYLE>
<STYLE>
body {
margin: 0px;
}
#doc-contents {
margin: 6px;
}
#google-view-footer {
clear: both;
border-top: thin solid;
padding-top: 0.3em;
padding-bottom: 0.3em;
}
a.google-small-link:link, a.google-small-link:visited {
color:#112ABB;
font-family:Arial,Sans-serif;
font-size:11px !important;
}
body, p, div, td {
direction: inherit;
}
@media print {
#google-view-footer {
display: none;
}
}
</STYLE>
<SCRIPT>
function viewOnLoad() {
if (document.location.href.indexOf('spi=1') != -1) {
if (navigator.userAgent.toLowerCase().indexOf('msie') != -1) {
window.print();
} else {
window.setTimeout(window.print, 10);
}
}
if (document.location.href.indexOf('hgd=1') != -1) {
var footer = document.getElementById("google-view-footer");
if (footer) {
footer.style.display = 'none';
}
}
}
</SCRIPT>
</HEAD><BODY onload="window.jstiming.load.tick(&#39;ol&#39;); window.jstiming.report(window.jstiming.load, null, document.location.protocol == &#39;https:&#39; ? &#39;https://gg.google.com/csi&#39; : null);">
<DIV id="doc-contents">
<DIV style="text-align: center;"><H1>TimeScore - System for Processing Time-weighted Scores</H1>August, 21, 2009<BR><DIV style="text-align: left;"><H2 style="font-weight: normal;"><B>Background</B></H2>Diverse systems have a requirement to calculate relative popularity or relevance based on sequences of events that occur throughout time over a population of entities to which these events are assigned.&nbsp; The general pattern assigns scores (or weights) to distinct events, and then accumulates these scores over time to derive a net score.&nbsp; The system can assign relative popularity or relevance to entities based on their relative net scores.<BR><BR>For example, a information processing system may contain a collection of news stories (entities).&nbsp; The events can consist of people selecting the most interesting headlines to read, rating the quality of the news story based on interesting-ness or relevance, recommending that their friends read the news story.&nbsp; Each event can be assigned a distinct weighted score (e.g., selecting a story to read can have a score of 1.0, while recommending&nbsp; story to a friend can carry a score of 3.0).<BR><BR>If each event is assigned a numerical score, the entities can record a net score based on the accumulated scores of all past events.<BR><BR>The problem with a simple adding up of all event scores, is that the element of time is not taking into account.&nbsp; A news story may exist in the system for a period of days, months, or years.&nbsp; What was interesting or "news" today, ceases to be so tomorrow.&nbsp; We desire a system that can adjust the event weights to take into account that more recent events should be weighted more highly than past events.<BR><BR>One approach is to "depreciate" all past scores stored in the system at specified time intervals (e.g., once per day).&nbsp; This has the disadvantage that the information system must read and modify all of the scores stored in the system each day to adjust them.&nbsp; Systems can reduce this workload by expiring entities from the system, but they risk loosing track of surges in popularity that may occur well after the expiration date of an entity.<BR><BR>Another approach is to keep a record of all recent scoring events, ordered by time.&nbsp; Periodically (e.g., nightly), net scores can be recalculated based on accumulating just the scores from the most recent time interval.&nbsp; It is expensive to process all scoring events (or even a summary of recent scoring events) until the event information can be discarded or ignored (after an system-defined maximum age).<BR><H2>Exponential Inflation</H2>A more efficient approach is to define a baseline time, on which all
scores will be interpreted.&nbsp; We then use an "inflation" model to
increase the weights that are applied to individual events, so that an
event occurring today, is given a higher relative weight to the same
event occurring in the past.<BR>
<BR>
In this approach, entities that are no longer receiving scoring events,
need not be read or updated, yet their scores can be compared against
more active entities to determine which are the most popular or
relevant.&nbsp; This has the benefit that most databases have a method of efficiently retrieving values in descending value of an attribute of an entity (e.g., ISAM databases, SQL-based indexes, or Google AppEngine Model indexes).<BR><BR>A very desirable model for comparing time based scores is to apply an exponentially increasing weighting factor to event scores.&nbsp; Exponential growth valuations are common in financial calculations (compound interest and Net Present Value calculations).&nbsp; A baseline time is chosen (the earliest time for which all events in the system can occur), and assigned a weight of one (1).&nbsp; Future weights are calculated as an exponentially increasing function of time.<BR><BR>Exponential functions can be characterized by a <I>half-life</I>, the time over which the value of the weighting function exactly doubles.&nbsp; The difficulty of processing values that grow exponentially is that the required storage for values increases linearly over time (or exceeds the available space allocated to store each value, e.g., if using a floating point numeric representation).<BR><BR>To address this concern, the preferred embodiment stores the logarithm of the score, rather than the score itself.&nbsp; Since logarithms are monotonically increasing&nbsp; functions, a value, v1, that is greater than another, v1, will have a logarithm log(v1), that is greater than the logarithm, log(v2) of the other value, i.e.:<BR><BR><DIV style="text-align: center;">v1 &gt; v2 iff log(v1) &gt; log(v2) | for all values v1, v2 &gt; 0<BR><BR><DIV style="text-align: left;">Any database index created based on the log of the scores for each entity, will order values in the same order as an index created over the scores themselves.<BR><H2 style="font-weight: normal;"><B>Preferred Embodiment<BR></B></H2>In order to efficiently calculate, time-weighted exponentially increasing scores, this embodiment stores 3 values for each entity:<BR><BR><OL><LI>t: The time the last scoring event was accumulated.</LI><LI>Q: The quotient, the score, and the current time-weight<BR></LI><LI>LogS: The log of the accumulated score, S.<BR></LI></OL><BR>In order to update the score of an entity, given a new event score, V2, at time t2, the following calculations are performed (assume our time-weight function has half-life, h).<BR><BR><DIV style="margin-left: 40px;">If t2 &gt; t:<BR></DIV><DIV style="margin-left: 40px;"><DIV style="margin-left: 40px;"><BR><BR></DIV><DIV id="q701" style="text-align: left;"><DIV style="margin-left: 40px;"><IMG style="width: 287px; height: 83px;" src="./TimeScore - System for Proces..._files/File"><BR><BR><DIV id="hzk8" style="text-align: left;"><IMG style="width: 78px; height: 26px;" src="./TimeScore - System for Proces..._files/File(1)"></DIV><BR><BR></DIV><BR>else if t2 &lt; t (update for an <I>older</I> event):<BR><BR></DIV><DIV id="j7n:" style="text-align: left; margin-left: 40px;"><IMG style="width: 287px; height: 83px;" src="./TimeScore - System for Proces..._files/File(2)"><BR><BR><BR></DIV><DIV id="z8y." style="text-align: left;"><DIV id="myyr" style="text-align: left;"><IMG style="width: 287px; height: 67px;" src="./TimeScore - System for Proces..._files/File(3)"></DIV><BR></DIV><BR></DIV><DIV style="margin-left: 40px;"><BR></DIV>An implementation of the <A title="TimeScore algorithm in Python" href="http://g02me.googlecode.com/svn/trunk/app/timescore/calc.py" id="y3ce">TimeScore algorithm in Python</A>:<BR><BR><DIV id="htlc" style="text-align: left;"><IMG style="width: 648px; height: 564.594px;" src="./TimeScore - System for Proces..._files/File(4)"></DIV><BR><H2>Differential TimeScores - Trending Scores<BR></H2>TimeScores can also be used to automatically identify <I>trending</I> scores with a score dataset.&nbsp; By calculating timescores over multiple half-life intervals (say, 1 day, 1 week, 1 month, and 1 year), the ratio of scores over different time scales can be used as an indicator of near-term or <I>trending</I> popularity.<BR><BR>Say, for example, that an entity regularly receives 10 units of score added to it each day.&nbsp; On a normal day, the ratio of the daily to the weekly score will roughly constant.&nbsp; But, if activity for this entity spikes to, say, twice it's normal level, then the ratio of daily to weekly scores will increase by a factor of 2.<BR><BR><DIV style="margin-left: 40px;">T = Sd/Sw&nbsp; (Trend defined as ratio of Daily to Weekly Score)<BR><BR></DIV>Since we are already storing the Log's of the time scores, we can easily also store and index our data set by the difference of two time scores to order or data set by the Trend value.<BR><BR><DIV style="margin-left: 40px;">LogT = Log(Sd) - Log(Sw)<BR></DIV><BR><H3>Base-line Normalized Trending</H3>In statistics, deviations from the norm are often expressed as the square of the deviation.&nbsp; In the same way, the trending function of interest may be defined as a higher power of the trend ratio, for example, as the square of the ratio of two TimeScores:<BR><BR><DIV style="margin-left: 40px;">T2 = (Sd/Sw)^2<BR><BR></DIV>This allows us to <I>normalize</I> trend data to preferentially have higher scores for entities that have highy baseline scores:<BR><BR><DIV style="margin-left: 40px;">T' = T2 * Sw<BR><BR>Log T' = 2 * Log(Sd) - Sw<BR><BR></DIV>This technique allows us to highlight those entities that already have a relatively high baseline score more heavily, and yet still allow low-scoring entities rank highly if their near-term Trend value is large enough.<BR><BR><H2>Claims<BR></H2></DIV></DIV><OL><LI>A method for processing scoring events for a plurality of records comprising:</LI><OL type="a"><LI>providing a data storage means which is able to store a collection of records including attributes for a last updated time, T, a current aggregate score, LS, and normalized score, Q,</LI><LI>providing a characteristic half-life, H,</LI><LI>providing a base, K, defined as (1/2)^(1/H),<BR></LI><LI>providing a query means whereby records can be retrieved from said data storage means according to the numerical ordering of an attribute of said records,</LI><LI>providing a data input queue means through which a series of event data can be retrieved comprising a record identifier, time, TR, and value, V, for each event,</LI><LI>providing processors which are connected to the said data storage means which can read and update said records, and can remove individual event data from said data input queue means and will:</LI><OL><LI>retrieve the record identified by the said record identifier, and<BR></LI><LI>calculate a new attributes as either:</LI><OL><LI>Q = V + K^(T-TR) * Q, and T = TR, if TR is greater than or equal to T, or</LI><LI>Q = K^(T-TR) * V + Q if TR is less than or equal to T and,</LI></OL><LI>calculate new attribute LS = log(Q) + T/H, and</LI><LI>store updated record back to said data storage means,<BR></LI></OL><LI>providing an output report comprising the ordered collection of records from said query means, where the query is ordered by descending order of the the aggregate score attributes of said records,</LI></OL></OL><DIV style="margin-left: 40px;">whereby said report will contain <BR></DIV><BR></DIV><DIV style="text-align: left;"><OL start="2"><LI>Method of claim 1 where LS is used as a key to create an queryable index in a database.<BR></LI><LI>The method of claim 1 wherein said output report if further restricted to retrieve only those records whose one or more other attributes are constrained to be equal to a specific value.</LI><LI>The method of claim 1 wherein said output report is limited to contain a fixed number of records comprising a prefix of the complete ordered list of records.</LI></OL><BR><I>There may be a way to generalize the above claim 1 and break down this way:<BR><BR></I><OL><LI><I>Weight scores and exponential function of time based on a fixed time base.</I></LI><LI>method of 1 where logarithm used for compression of aggregate scores</LI><LI>method of 2 where t/Q/LS calculation method is used to calculate aggregate scores</LI><LI>method of 3 where reported scores are displayed normalized to the user's current time (virtual depreciation)</LI><LI>method of claim 3 where scores are normalized by (1-k) factor - scaling aggregate score to be equal to a steady stream of constant values in each period.<BR></LI></OL><BR>Other dependent claims:<BR><BR><OL><LI>Simultaneous calcuation of scores with different half-lives (day, week, month, year) to provide different time-scale reporting.</LI><LI>Calculation and indexing on Trend value defined as the ratio of a TimeScore with a smaller half life and a TimeScore with a longer half-life.</LI><LI>Calculation and indexing of Trend-Squared emphasizing larger excursions from the normal TimeScore value.</LI><LI>Calculation and indexing of Trend-Squared TIMES TimeScore baseline, highlight Trending entities, but preferentially those that already have a relatively high TimeScore baseline value a the longer time scale (half-life).<BR></LI><LI>Storing multiple dimensions of timescore data - combining via sums
and differences (for positive and negative scoring dimensions) -
equivalent to products and quotients of underlying scores</LI><LI>Using tags to define partitions of dataset (but sharing same underlying timescores)</LI><LI>method of changing the (previously fixed) half-life for all future scores w/o having to recalculate original scores</LI></OL><BR><HR class="pb"><BR><BR>Equation expressions for <A href="http://www.sitmo.com/latex/">http://www.sitmo.com/latex/</A> here:<BR><BR>Q=V_2 + \frac{1}{2}^\frac{(t_2-t)}{h}*Q <BR>t = t_2<BR><BR>Q=\frac{1}{2}^\frac{(t_2-t)}{h}*V_2+Q <BR><BR>LogS = log_2(Q) + \frac{t}{h}<BR><BR>(capture + and - scoring system)<BR></DIV></DIV>(incuding flitering by tags)<BR>
<BR clear="all">
</DIV>
<DIV id="google-view-footer">
<DIV id="maybecanedit" style="float:right">
<A class="google-small-link" id="editpermissionlink" href="http://docs.google.com/a/mckoss.com/Doc?tab=edit&dr=true&id=dg7jwgdn_5ck94x5gp" title="Edit this page">
Edit this page (if you have permission)</A>
<SPAN style="color:#676767;">|</SPAN>
<INPUT id="report-abuse-button" type="button" value="Report abuse" onclick="reportAbuse();">
</DIV>
<DIV style="float:left">
<A title="Learn more about Google Docs" class="google-small-link" href="http://docs.google.com/a/mckoss.com/">
Google Docs -- Web word processing, presentations and spreadsheets.</A>
</DIV>
<P> &nbsp;
</P></DIV>
<SCRIPT><!--
    viewOnLoad();
    if(window.jstiming){window.jstiming.a={};window.jstiming.c=1;function g(a,b,f){var c=a.t[b];if(!c)return undefined;c=a.t[b][0];if(f!=undefined)a=f;else a=a.t.start[0];return c-a}window.jstiming.report=function(a,b,f){var c="";if(window.jstiming.pt){c+="&srt="+window.jstiming.pt;delete window.jstiming.pt}try{if(window.external&&window.external.tran)c+="&tran="+window.external.tran;else if(window.gtbExternal&&window.gtbExternal.tran)c+="&tran="+window.gtbExternal.tran()}catch(o){}if(a.b)c+="&"+a.b;
var e=a.t,n=e.start,k=[],h=[],i=[];for(var d in e)if(!(d=="start"))if(!(d.indexOf("_")==0)){var j=e[d][1];if(j){if(e[j]){h.push(d+"."+g(a,d,e[j][0]));i.push(g(a,d))}}else n&&k.push(d+"."+g(a,d))}delete e.start;if(b)for(var l in b)c+="&"+l+"="+b[l];a=[f?f:"http://csi.gstatic.com/csi","?v=3","&s="+(window.jstiming.sn||"writely")+"&action=",a.name,h.length?"&it="+h.join(","):"",i.length?"&irt="+i.join(","):"",c,"&rt=",k.join(",")].join("");b=new Image;var m=window.jstiming.c++;window.jstiming.a[m]=b;
b.onload=b.onerror=function(){delete window.jstiming.a[m]};b.src=a;b=null;return a}};

    window.jstiming.load.name = 'published';
    
    
    var urchinPage = "/View";

    
    function getXHR() {
      if (typeof XMLHttpRequest != "undefined") {
        return new XMLHttpRequest();
      }
      try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
      try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
      try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
      try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
      return null;
    }

    function reportAbuse() {
      var req = getXHR();
      if (req) {
        
          var docid = 'dg7jwgdn_5ck94x5gp';
          var posttoken = 'NExdMCQBAAA.cqrxyKYmLQjYDfvOMGBW5w.e0YnpnNUfUhKR6EaQbC8Ag';
        
        req.onreadystatechange = function() {
          try {
            if (req.readyState == 4 && req.status == 200) {
              var button = document.getElementById("report-abuse-button");
              button.value = 'Thank you!';
              button.disabled = true;
            }
          } catch (ex) {
            
          }
        }
        try {
          req.open('POST', 'MiscCommands', true);
          req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
          req.send('command=report_abuse&abuseDoc=' + encodeURIComponent(docid) +
                   '&POST_TOKEN=' + encodeURIComponent(posttoken));
        } catch (ex) {
          
        }
      }
    }
  --></SCRIPT>


</BODY></HTML>